package cool.houge.pig.infra.service;

import com.google.common.base.Objects;
import com.google.common.base.Strings;
import cool.houge.pig.PigProps;
import cool.houge.pig.model.AuthClient;
import cool.houge.pig.repository.auth.AuthAccessTokenRepository;
import cool.houge.pig.repository.auth.AuthAuthorizationCodeRepository;
import cool.houge.pig.repository.auth.AuthClientRepository;
import cool.houge.pig.repository.auth.AuthRefreshTokenRepository;
import cool.houge.pig.service.auth.AccessTokenDetails;
import cool.houge.pig.service.auth.AuthTokenException;
import cool.houge.pig.service.auth.AuthTokenException.Error;
import cool.houge.pig.service.auth.SharedAuthService;
import java.util.Arrays;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;

/**
 * 认证服务实现.
 *
 * @author KK (kzou227@qq.com)
 */
@Service
public class AuthServiceImpl implements SharedAuthService {

  private final PigProps pigProps;
  private final AuthClientRepository authClientRepository;
  private final AuthAccessTokenRepository authAccessTokenRepository;
  private final AuthRefreshTokenRepository authRefreshTokenRepository;
  private final AuthAuthorizationCodeRepository authAuthorizationCodeRepository;

  /**
   * @param pigProps
   * @param authClientRepository
   * @param authAccessTokenRepository
   * @param authRefreshTokenRepository
   * @param authAuthorizationCodeRepository
   */
  public AuthServiceImpl(
      PigProps pigProps,
      AuthClientRepository authClientRepository,
      AuthAccessTokenRepository authAccessTokenRepository,
      AuthRefreshTokenRepository authRefreshTokenRepository,
      AuthAuthorizationCodeRepository authAuthorizationCodeRepository) {
    this.pigProps = pigProps;
    this.authClientRepository = authClientRepository;
    this.authAccessTokenRepository = authAccessTokenRepository;
    this.authRefreshTokenRepository = authRefreshTokenRepository;
    this.authAuthorizationCodeRepository = authAuthorizationCodeRepository;
  }

  @Override
  public Mono<AuthClient> findAuthClient(String clientId) {
    return authClientRepository
        .findByClientId(clientId)
        .switchIfEmpty(
            Mono.error(
                () ->
                    new AuthTokenException(
                        Error.INVALID_CLIENT, Strings.lenientFormat("未知的认证客户端[%s]", clientId))));
  }

  @Override
  public Mono<AuthClient> obtainAuthClient(String clientId, String clientSecret, String grantType) {
    return findAuthClient(clientId)
        .doOnNext(
            authClient -> {
              if (!Objects.equal(authClient.getClientSecret(), clientSecret)) {
                throw new AuthTokenException(Error.INVALID_CLIENT, "客户端认证失败");
              }
              if (authClient.getAllowGrantType() == null) {
                throw new AuthTokenException(Error.UNAUTHORIZED_CLIENT, "该客户端ID不支持认证");
              }
              // * 代表所有认证类型
              if (!"*".equals(authClient.getAllowGrantType())) {
                // 多个认证类型采用逗号分隔
                String[] allowGrantTypes = authClient.getAllowGrantType().split(",");
                if (Arrays.binarySearch(allowGrantTypes, grantType) < 0) {
                  throw new AuthTokenException(
                      Error.UNAUTHORIZED_CLIENT,
                      Strings.lenientFormat("客户端不支持该授权类型[%]", grantType));
                }
              }
            });
  }

  @Override
  public Mono<String> makeAccessToken(long uid, String clientId, String scope) {
    return null;
  }

  @Override
  public Mono<AccessTokenDetails> parseAccessToken(String accessToken) {
    return null;
  }
}
